/*******************************************************************************
* Copyright (c) 2012, Project: FP7-ICT-257930 Aniketos
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of institution nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package eu.aniketos.mtm.srs2activiti.wizard.pages;
import java.util.ArrayList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;
import eu.aniketos.mtm.Activator;
import eu.aniketos.mtm.idm.client.IdMClient;
import eu.aniketos.mtm.idm.client.implementation.IdMClientImplementation;
import eu.aniketos.mtm.mapping.BPPType;
import eu.aniketos.mtm.mapping.BPRType;
import eu.aniketos.mtm.mapping.IsaType;
import eu.aniketos.mtm.mapping.MappingType;
import eu.aniketos.mtm.mapping.SRAType;
import eu.aniketos.mtm.mapping.TypeType;
import eu.aniketos.mtm.srs.AgentType;
import eu.aniketos.mtm.srs.SecReqSpeType;
import eu.aniketos.mtm.srs2activiti.wizard.Srs2ActivitiWizard;
import eu.aniketos.mtm.util.MappingManager;
import eu.aniketos.mtm.util.SrsManager;
/**
*
* Page used to establish the correspondences between SRS agents and BPMN participants (1:n relationship).
*
*/
public class NewPerformersPage extends CustomPage {
private static final String PREFIX_AGENT = "agent_";
private static final String PREFIX_ROLE = "role_";
public static final String PERFORMERTYPE_SERVICE = "Service Provider";
public static final String PERFORMERTYPE_HUMAN = "Human Performer";
// Input SRS agents
private ArrayList<AgentType> agentList;
// List of composites, every of which contain all the participants that match an agent
private ArrayList<Composite> activitiCompositeMainList;
// List of types
private ArrayList<ArrayList<Combo>> performerTypeList;
// List of roles
private ArrayList<ArrayList<Combo>> performerRoleList;
// List of participant names
private ArrayList<ArrayList<Combo>> performerValueList;
// List of buttons for removing a participant
private ArrayList<ArrayList<Button>> removeButtonList;
// List of buttons for adding a new participant to an agent
private ArrayList<Button> addButtonList;
// Main scrollable composite
private ScrolledComposite scrollComposite;
private IdMClient idMClient;
private String[] humanRoles = {};
private String[] serviceRoles = {};
private String[] roleTypes = {PERFORMERTYPE_SERVICE, PERFORMERTYPE_HUMAN};
/**
* Constructor.
* @param srs The SecReqSpeType root SRS element to be transformed.
*/
public NewPerformersPage(SecReqSpeType srs) {
super("NewPerformersPage");
setTitle("Performers mapping");
setDescription("Map SRS Agents to BPMN Performers");
agentList = SrsManager.getInstance().extractAgentList(srs);
int sizeList = agentList.size();
activitiCompositeMainList = new ArrayList<Composite>(sizeList);
performerTypeList = new ArrayList<ArrayList<Combo>>(sizeList);
performerRoleList = new ArrayList<ArrayList<Combo>>(sizeList);
performerValueList = new ArrayList<ArrayList<Combo>>(sizeList);
removeButtonList = new ArrayList<ArrayList<Button>>(sizeList);
addButtonList = new ArrayList<Button>(sizeList);
// Get MTM preference for IDM
String pathIdM = Activator.getDefault().getPreferenceStore().getString("IdM_file_path");
idMClient = new IdMClientImplementation(pathIdM);
}
/**
*
*/
@Override
public void createControl(Composite parent) {
scrollComposite = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
Composite composite = new Composite(scrollComposite, SWT.FILL);
GridLayout gl = new GridLayout();
gl.numColumns = 2;
composite.setLayout(gl);
// Main control skeleton for the agent/participant correspondence
createMainControls(composite);
// Scrollable parent composite
scrollComposite.setContent(composite);
scrollComposite.setExpandVertical(true);
scrollComposite.setExpandHorizontal(true);
scrollComposite.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
updateScroll();
}
});
addListeners();
setControl(scrollComposite);
setPageComplete(isReady());
}
/**
* Creates the main control skeleton for the agent/participant correspondence.
* @param composite The parent composite
*/
private void createMainControls(Composite composite) {
if(isEmpty()) {
// No agents found
Label emptyLabel = new Label(composite, SWT.NULL);
emptyLabel.setText("No SRS Agents found");
return;
}
GridData gd;
// Column titles
Label agentsLabel = new Label(composite, SWT.NULL);
agentsLabel.setText("SRS Agents");
gd = new GridData();
gd.horizontalAlignment = SWT.FILL;
Label activitiLabel = new Label(composite, SWT.NULL);
activitiLabel.setText("ACTIVITI Performers");
activitiLabel.setLayoutData(gd);
performerTypeList.clear();
performerRoleList.clear();
performerValueList.clear();
// For every agent...
for (int i = 0; i < agentList.size(); i++) {
// Fill agent description labels
AgentType agent = agentList.get(i);
String agentValue = agent.getValue().trim();
String agentString = agentValue;
Label agentIdLabel = new Label(composite, SWT.NULL);
agentIdLabel.setText(agentString);
Composite compositeActiviti = new Composite(composite, SWT.BORDER);
compositeActiviti.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
compositeActiviti.setLayout(new GridLayout(1, false));
Composite compositeMainActiviti = new Composite(compositeActiviti, SWT.NULL);
compositeMainActiviti.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
compositeMainActiviti.setLayout(new GridLayout(1, false));
activitiCompositeMainList.add(compositeMainActiviti);
// Add the first participant controls for this agent
addPerformerRecord(agentValue, i);
// Button for adding a new participant
Button addButton = new Button(compositeActiviti, SWT.NONE);
addButton.setText("Add new");
addButtonList.add(addButton);
}
onAppear();
}
/**
* Adds the controls needed for one new participant.
* @param performerValue The suggested name of the participant.
* @param index The index of the corresponding agent.
*/
private void addPerformerRecord(String performerValue, int index) {
if (index >= agentList.size()) {
return;
}
// Get a reference to the composite that contain all the participants that match an agent
Composite composite = activitiCompositeMainList.get(index);
Composite compositeSingleActiviti = new Composite(composite, SWT.NULL);
compositeSingleActiviti.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
compositeSingleActiviti.setLayout( new GridLayout(4, false));
Composite typeComboComposite = new Composite(compositeSingleActiviti, SWT.NULL);
typeComboComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
typeComboComposite.setLayout(new GridLayout(2, false));
// Participant type
Label typeLabel = new Label(typeComboComposite, SWT.NULL);
typeLabel.setText("Performer type");
Combo typeCombo = new Combo(typeComboComposite, SWT.BORDER | SWT.READ_ONLY);
typeCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
typeCombo.setItems(this.roleTypes);
typeCombo.setData(index+"");
typeCombo.select(0);
typeCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateRoleCombo (e.widget);
}
});
Composite roleComboComposite = new Composite(compositeSingleActiviti, SWT.NULL);
roleComboComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
roleComboComposite.setLayout(new GridLayout(2, false));
// Performer role
Label performerRoleLabel = new Label(roleComboComposite, SWT.NULL);
performerRoleLabel.setText("Role name");
Combo roleCombo = new Combo(roleComboComposite, SWT.BORDER | SWT.READ_ONLY);
roleCombo.setLayoutData(new GridData(SWT.FILL, SWT.LEFT, true, false));
roleCombo.setData(index+"");
roleCombo.setItems(serviceRoles);
roleCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateAgentCombo (e.widget);
}
});
Composite agentComboComposite = new Composite(compositeSingleActiviti, SWT.NULL);
agentComboComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
agentComboComposite.setLayout(new GridLayout(2, false));
// Performer agent value
Label performerValueLabel = new Label(agentComboComposite, SWT.NULL);
performerValueLabel.setText("Agent name");
Combo agentCombo = new Combo(agentComboComposite, SWT.BORDER | SWT.READ_ONLY);
agentCombo.setLayoutData(new GridData(SWT.FILL, SWT.LEFT, true, false));
agentCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setPageComplete(isReady());
}
});
// Add the participant combos to performerTypeList, performerRoleList and performerValueList
ArrayList<Combo> performerTypeSubList = null;
ArrayList<Combo> performerRoleSubList = null;
ArrayList<Combo> performerValueSubList = null;
if (index >= performerValueList.size()) {
// First participant for an agent
performerTypeSubList = new ArrayList<Combo>(1);
performerRoleSubList = new ArrayList<Combo>(1);
performerValueSubList = new ArrayList<Combo>(1);
performerTypeList.add(performerTypeSubList);
performerRoleList.add(performerRoleSubList);
performerValueList.add(performerValueSubList);
} else {
performerTypeSubList = performerTypeList.get(index);
performerRoleSubList = performerRoleList.get(index);
performerValueSubList = performerValueList.get(index);
}
performerTypeSubList.add(typeCombo);
performerRoleSubList.add(roleCombo);
performerValueSubList.add(agentCombo);
// Create a button to remove this participant row
Button removeButton = new Button(compositeSingleActiviti, SWT.NONE);
removeButton.setText("Remove");
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
int index = -1;
int subIndex = -1;
for(int i = 0; i < removeButtonList.size(); i++) {
ArrayList<Button> buttonList = removeButtonList.get(i);
subIndex = buttonList.indexOf(e.widget);
if(subIndex >= 0) {
index = i;
break;
}
}
if(index >= 0) {
removePerformerRecord(index, subIndex);
}
}
});
// Add the remove button to removeButtonList
ArrayList<Button> removeSubList = null;
if (index >= removeButtonList.size()) {
// First participant for an agent
removeSubList = new ArrayList<Button>(1);
removeButtonList.add(removeSubList);
} else {
removeSubList = removeButtonList.get(index);
}
removeSubList.add(removeButton);
// Enable the remove buttons only where there is more than one participant for an agent
updateRemoveButtons(index);
// Refresh the screen
refresh();
// Declare the page as complete when the form is full-filled
setPageComplete(isReady());
}
private void updateRoleCombo(Widget widget) {
if(widget instanceof Combo){
Combo typeCombo = (Combo) widget;
String index = (String) typeCombo.getData();
int i = new Integer(index).intValue();
ArrayList<Combo> performerTypeSubList = performerTypeList.get(i);
int subindex = performerTypeSubList.indexOf(typeCombo);
if(subindex >= 0) {
Combo performerRoleCombo = performerRoleList.get(i).get(subindex);
performerRoleCombo.clearSelection();
String selectedType = typeCombo.getText();
if(selectedType.equals(PERFORMERTYPE_SERVICE)){
performerRoleCombo.setItems(serviceRoles);
}
else if (selectedType.equals(PERFORMERTYPE_HUMAN)){
performerRoleCombo.setItems(humanRoles);
}
}
}
}
private void updateAgentCombo (Widget widget){
if(widget instanceof Combo){
Combo roleCombo = (Combo) widget;
String index = (String) roleCombo.getData();
int i = new Integer(index).intValue();
ArrayList<Combo> performerRoleSubList = performerRoleList.get(i);
int subindex = performerRoleSubList.indexOf(roleCombo);
if(subindex >= 0) {
Combo performerTypeCombo = performerTypeList.get(i).get(subindex);
String selectedType = performerTypeCombo.getText();
Combo performerAgentCombo = performerValueList.get(i).get(subindex);
performerAgentCombo.clearSelection();
String selectedRole = roleCombo.getText();
String agents = null;
if(selectedType.equals(PERFORMERTYPE_SERVICE)){
agents = idMClient.getMembersOfServiceGroup(selectedRole);
}
else if(selectedType.equals(PERFORMERTYPE_HUMAN)){
agents = idMClient.getMembersOfHumanGroup(selectedRole);
}
performerAgentCombo.setItems(splitSringToList(agents));
}
}
}
/**
* Removes one participant's controls.
* @param index The index of the agent it belongs to.
* @param subIndex The index of the participant for this agent.
*/
private void removePerformerRecord(int index, int subIndex) {
if (index >= agentList.size()) {
return;
}
// Remove the references to the controls from the member lists
performerValueList.get(index).remove(subIndex);
performerTypeList.get(index).remove(subIndex);
performerRoleList.get(index).remove(subIndex);
removeButtonList.get(index).remove(subIndex);
// Remove the parent composite from the page
Composite mainComposite = activitiCompositeMainList.get(index);
Composite composite = (Composite)mainComposite.getChildren()[subIndex];
composite.dispose();
// Enable the remove buttons only where there is more than one participant for an agent
updateRemoveButtons(index);
// Refresh the screen
refresh();
// Declare the page as complete when the form is full-filled
setPageComplete(isReady());
}
@Override
public void onAppear() {
super.onAppear();
refreshList();
updateControls();
setPageComplete(isReady());
}
public void refreshList (){
String humanList = idMClient.getGroupsListOfHuman();
humanRoles = splitSringToList(humanList);
String serviceList = idMClient.getGroupsListOfService();
serviceRoles = splitSringToList(serviceList);
}
private String[] splitSringToList(String s){
String[] array = s.split(",");
return array;
}
private void updateControls(){
for (ArrayList<Combo> comboList : performerValueList) {
int index = performerValueList.indexOf(comboList);
for (Combo combo : comboList) {
int subindex = comboList.indexOf(combo);
int selectionIndex = combo.getSelectionIndex();
Combo typeCombo = this.performerTypeList.get(index).get(subindex);
Combo roleCombo = performerRoleList.get(index).get(subindex);
String selectedType = null;
if(selectionIndex != -1){
selectedType = typeCombo.getText();
String selectedRole = roleCombo.getText();
selectionIndex = findRoleIndex(selectedRole, selectedType);
if(selectedType.equals(PERFORMERTYPE_SERVICE)){
roleCombo.setItems(serviceRoles);
}
else if(selectedType.equals(PERFORMERTYPE_HUMAN)){
roleCombo.setItems(humanRoles);
}
}
else{
roleCombo.setItems(serviceRoles);
}
roleCombo.select(selectionIndex);
}
}
}
private int findRoleIndex(String role, String type){
if(type.equals(PERFORMERTYPE_SERVICE)){
for (int i = 0; i < serviceRoles.length; i++) {
String serviceRole = serviceRoles[i];
if(serviceRole.equals(role)){
return i;
}
}
}
else if (type.equals(PERFORMERTYPE_HUMAN)){
for (int i = 0; i < humanRoles.length; i++) {
String humanRole = humanRoles[i];
if(humanRole.equals(role)){
return i;
}
}
}
return 0;
}
/**
* Refresh the page to show the last changes.
*/
private void refresh() {
Shell shell = getShell();
shell.layout(true, true);
updateScroll();
}
/**
* Adds listeners to controls.
*/
private void addListeners() {
addAgentListeners();
}
/**
* Adds the suitable listener to every Add button.
*/
private void addAgentListeners() {
for (int i = 0; i < addButtonList.size(); i++) {
Button addButton = addButtonList.get(i);
addButton.addSelectionListener(new AddSelectionAdapter(i));
}
}
/**
*
*/
@Override
public boolean isEmpty() {
return agentList.size() == 0;
}
/**
* Updates the mapping model.
*/
@Override
protected void pageComplete() {
updateModel();
}
/**
*
*/
@Override
public boolean canFlipToNextPage() {
return isPageComplete();
}
/**
* Finish button disabled.
*/
@Override
public boolean canFinish() {
return false;
}
/**
* Checks whether the form is full-filled.
* @return True when full-filled, false when a Text control is empty.
*/
private boolean isReady() {
for (ArrayList<Combo> array : performerValueList) {
for (Combo combo : array) {
if (!isComboNonEmpty(combo)) {
setErrorMessage("There are empty fields.");
return false;
}
else{
setErrorMessage(null);
}
}
}
return true;
}
/**
* Updates the enabled/disabled state of all Remove buttons.
*/
private void updateAllRemoveButtons() {
for(int i = 0; i < removeButtonList.size(); i++) {
updateRemoveButtons(i);
}
}
/**
* Sets Remove buttons enabled only when there is more than one participant for one agent.
* @param index The index of the agent.
*/
private void updateRemoveButtons(int index) {
ArrayList<Button> buttonList = removeButtonList.get(index);
boolean enabled = false;
if(buttonList.size() > 1) {
enabled = true;
}
for(Button button : buttonList) {
button.setEnabled(enabled);
}
}
/**
* Updates the main scrollbar.
*/
private void updateScroll() {
Rectangle r = scrollComposite.getClientArea();
scrollComposite.setMinSize(scrollComposite.getChildren()[0].computeSize(r.width, SWT.DEFAULT));
}
/**
* Updates the mapping model based on the page form.
*/
private void updateModel() {
int size = agentList.size();
if(size > 0) {
MappingType mapping = ((Srs2ActivitiWizard)getWizard()).getMapping();
MappingManager manager = MappingManager.getInstance();
// Clear the existing is-a relationships
manager.resetIsAList(mapping);
// For every agent...
for (int i = 0; i < size; i++) {
AgentType agent = agentList.get(i);
// Create the agent mapping element
SRAType sra = manager.createSRAgent(agent.getId().toString(), agent.getValue().trim());
ArrayList<Combo> performerValueSublist = performerValueList.get(i);
int subSize = performerValueSublist.size();
// For every participant binded to this agent...
for (int j = 0; j < subSize; j++) {
Combo valueCombo = performerValueSublist.get(j);
// Get role type
Combo typeCombo = performerTypeList.get(i).get(j);
TypeType roleType = null;
if(typeCombo.getText().equals(PERFORMERTYPE_SERVICE)){
roleType = TypeType.SERVICE;
}
else if (typeCombo.getText().equals(PERFORMERTYPE_HUMAN)){
roleType = TypeType.HUMAN;
}
// Get role
Combo roleCombo = performerRoleList.get(i).get(j);
BPPType bpp = null;
BPRType bprType = null;
IsaType isaType = findRoleAGent(roleType, roleCombo.getText().trim(), valueCombo.getText().trim());
if(isaType == null){
// Create the participant mapping element
String agentId = PREFIX_AGENT + agent.getId() + "_" + j;
bpp = manager.createBPPart(agentId, valueCombo.getText().trim(), roleType);
String roleId = PREFIX_ROLE + agent.getId() + "_" + j;
bprType = manager.createBPRole(roleId, roleCombo.getText().trim(), roleType);
}
else{
// Clone the existing one
bpp = manager.createBPPart(isaType.getBPPart().get(0).getId(), valueCombo.getText().trim(), roleType);
bprType = manager.createBPRole(isaType.getBPRole().get(0).getId(), roleCombo.getText().trim(), roleType);
}
// Create and add the is-a relationship
IsaType isa = manager.createIsA(sra, bpp, bprType);
manager.addIsA(mapping, isa);
}
}
}
}
private IsaType findRoleAGent(TypeType roleType, String role, String agent) {
MappingType mapping = ((Srs2ActivitiWizard)getWizard()).getMapping();
for (IsaType isaType : mapping.getIsA()) {
BPPType bppType = isaType.getBPPart().get(0);
if(bppType.getType().equals(roleType) && bppType.getValue().equals(agent)){
BPRType bprType = isaType.getBPRole().get(0);
if(bprType.getType().equals(roleType) && bprType.getValue().equals(role)){
return isaType;
}
}
}
return null;
}
/**
*
* Adapter for Add button.
*
* @author Eneko Gomez <eneko.gomez@tecnalia.com>
*
*/
class AddSelectionAdapter extends SelectionAdapter {
int index;
/**
* Constructor.
* @param index The index of the agent.
*/
public AddSelectionAdapter(int index) {
this.index = index;
}
/**
* Adds the controls necessary for the new participant.
* Controls are empty by default.
*/
@Override
public void widgetSelected(final SelectionEvent e) {
AgentType agent = agentList.get(index);
String agentValue = agent.getValue().trim();
addPerformerRecord(agentValue, index);
}
}
}